#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <assert.h>
#include <cstdlib>
#include <time.h>

#include "task.hpp"
#define PROCESS_NUM 5

using namespace std;

int waitCommand(int fd,bool &quit)
{
    uint32_t command = 0;
    ssize_t s = read(fd,&command,sizeof command);
    if(s == 0) // 写端关闭
    {
        quit = true;
        return -1;
    }
    assert(s == sizeof command);
    return command;
}

void sendAndWakeUp(pid_t id,int fd,uint32_t command)
{
    write(fd,&command,sizeof command);
    cout << "main process: call process" << id << " excute " << mp[command] << " through " << fd << endl; 
}

/// @brief 
/// @return 
int main()
{
    // 加载命令
    load();
    // 储存子进程的的pid和对应父进程的写端pipefd[1];
    vector<pair<pid_t,int>> slot;
    // 创建子进程
    for(int i = 0;i < PROCESS_NUM;i++)
    {
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        assert(n != -1);
        (void)n;
        int id = fork();
        assert(id >= 0);
        if(id == 0)
        {
            // 关闭写端
            close(pipefd[1]);
            // child 等待命令
            while(true)
            {
                // 如果对方不发我们就阻塞 ps:read返回0，代表写端关闭
                // uint32_t command;
                // ssize_t ret = read(pipefd[0],&command,sizeof command);
                // assert(ret != -1);
                // if(ret == 0)
                // {
                //     break;
                // }
                bool quit = false;
                int command = waitCommand(pipefd[0],quit);
                if(quit == true)
                {
                    break;
                }
                if(command >= 0 && command < TaskNum())
                {
                    taskset[command]();
                }
                else
                {
                    cout << "command 非法指令"  << command << endl;
                }         
            }
            exit(1);       
        }
        // 父进程
        // 关闭读端
        close(pipefd[0]);
        slot.push_back(pair<pid_t,int>(id,pipefd[1]));

    }
        // 发送命令
        // 让命令变得随
        srand((unsigned long)time(nullptr) ^ 3249495840L ^ getpid());
        while(true)
        {
            uint32_t command = rand() % TaskNum();
            int procNum = rand() % slot.size();
            // write(pipefd[1],command,sizeof command); 这样写父进程拿不到pipefd
            // write(slot[procNum].second,&command,sizeof command);
            sendAndWakeUp(getpid(),slot[procNum].second,command);
            sleep(1);
        }

        // 关闭父进程写fd，所有的子进程都会退出
        for(const auto& fd : slot)
        {
            close(fd.second);
        }
        // 回收所有子进程信息
        for(const auto& pid : slot)
        {
            waitpid(pid.first,nullptr,0);
        }


    return 0;
}